<?php

namespace traits\model;

use helper\Tree;
use think\db\Query;
use think\facade\Db;

trait BaseTraits {

    /**
     * 通用搜索器
     * @param Query $query
     * @param $value
     * @param $data
     */
    public function searchFilterAttr(Query $query, $value, $data) {
        $filter = empty($value) ? [] : $value;
        $opArr  = [
            '=', '<>', '>', '>=', '<', '<=', 'like', 'not like', 'between', 'not between', 'in', 'not in',
            'null', 'not null', 'exists', 'not exists', 'find_in_set', '> time', '>= time', '< time',
            '<= time', 'between time', 'not between time', 'between time field', 'time', 'year',
            'month', 'week', 'day', '= column', '> column', '>= column', '< column', '<= column', 'exp',
            'left like', 'right like'
        ];
        if (isset($data['field'])) $query->field($data['field']); //字段设置
        if (isset($data['append'])) $query->append($data['append']);
        if (isset($data['hidden'])) $query->hidden($data['hidden']);
        foreach ($filter as $v) {
            if (empty($v) || count($v) !== 3) continue; //跳过不合格数组
            if (array_values($v) === $v) $v = ['field' => $v[0], 'op' => $v[1], 'value' => $v[2]]; //处理数字索引
            if (isset($v[0])) $v['field'] = $v[0];
            if (isset($v[1])) $v['op'] = $v[1];
            if (isset($v[2])) $v['value'] = $v[2];
            $field = preg_match("/^[a-z0-9_.|&]+$/", $v['field']) ? $v['field'] : '';
            $op    = isset($v['op']) ? in_array($v['op'], $opArr) ? $v['op'] : '' : '=';
            $val   = addslashes(trim($v['value'])); //转义特殊字符
            //验证合法性
            if (empty($op)) continue;
            if (in_array($op, ['null', 'not null'])) {
                if (empty($field)) continue;
            } else if (in_array($op, ['exists', 'not exists'])) {
                if (empty($val)) continue;
            } else {
                if (empty($field) || strlen($val) == 0) continue;
            }
            switch ($op) {
                case '=':
                case '<>':
                case '>':
                case '>=':
                case '<':
                case '<=':
                    $query->where($field, $op, (string)$val);
                    break;
                case 'like':
                    $query->whereLike($field, "%{$val}%");
                    break;
                case 'left like':
                    $query->whereLike($field, "{$val}%");
                    break;
                case 'right like':
                    $query->whereLike($field, "%{$val}");
                    break;
                case 'not like':
                    $query->whereNotLike($field, "%{$val}%");
                    break;
                case 'between':
                case 'not between':
                case 'in':
                case 'not in':
                    $query->where($field, $op, $val);
                    break;
                case 'null':
                    $query->whereNull($field);
                    break;
                case 'not null':
                    $query->whereNotNull($field);
                    break;
                case 'exists':
                    $val = Db::raw(stripslashes($val));
                    $query->whereExists($val);
                    break;
                case 'not exists':
                    $val = Db::raw(stripslashes($val));
                    $query->whereNotExists($val);
                    break;
                case 'find_in_set':
                    $query->whereFindInSet($field, $val);
                    break;
                case '> time':
                case '>= time':
                case '< time':
                case '<= time':
                    $op = str_replace(' time', '', $op);
                    $query->whereTime($field, $op, $val);
                    break;
                case 'between time':
                case 'not between time':
                    $val = explode(' - ', $val);
                    if (strlen($val[0]) <= 10) $val[0] .= ' 0:00:00';
                    if (strlen($val[1]) <= 10) $val[1] .= ' 23:59:59';
                    if ($op == 'between time') {
                        $query->whereBetweenTime($field, $val[0], $val[1]);
                    }
                    if ($op == 'not between time') {
                        $query->whereBetweenTime($field, $val[0], $val[1]);
                    }
                    break;
                case 'between time field':
                    $query->whereBetweenTimeField($field, $val);
                    break;
                case 'time':
                case 'year':
                case 'month':
                case 'week':
                case 'day':
                    $fun = 'where' . ucfirst($op);
                    $query->$fun($field, $val);
                    break;
                case '= column':
                case '> column':
                case '>= column':
                case '< column':
                case '<= column':
                    $op = str_replace(' column', '', $op);
                    $query->whereColumn($field, $op, $val);
                    break;
                case 'exp':
                    $query->whereExp($field, $val);
                    break;
                default:
                    break;
            }
        }
    }

  /**
   * 格式化获取树型数据
   * @param $list
   * @param string $field
   * @return array
   */
    public function formatTree($list,$field='name'){
      $treeList = $list;
      foreach ($list as $k => $v) {
        $child          = Tree::channelList($treeList, $v['id']); //取所有下级
        $v['has_child'] = 0; //默认无下级
        $v['path']      = $v['id']; //所有下级数据
        if (!empty($child)) {
          $v['path']      .= ',' . implode(',', array_column($child, 'id'));
          $v['has_child'] = 1;
        }
        $v['child'] = $child;
        $v['disabled'] = $v['class_type']==0?'':'disabled';
        $v['chkDisabled'] = $v['class_type']==0?false:true;
        $parent         = array_reverse(Tree::parentChannel($treeList, $v['id']));
        $v['location']  = $parent;
        $v['full_name'] = implode('/', array_column($parent, $field));
        $list[$k]       = $v;
      }
      $tree = Tree::tree($list, $field);
      return $tree;
    }

    /**
     * 获取视图字段
     * @param $tableName
     * @param string $withOutFields 要排除的字段','隔开
     * @return array
     */
    public function viewFields($tableName,$withOutFields=''){
        $fields = array_keys($this->getFields($tableName));
        if(!empty($outFields)){
            $fields = array_values(array_diff($fields, explode(',',$withOutFields)));
        }
        return $fields;
    }

}